home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Grab Bag
/
Shareware Grab Bag.iso
/
090
/
v7n13.arc
/
SETMODE.ASM
< prev
next >
Wrap
Assembly Source File
|
1988-07-01
|
27KB
|
967 lines
;======================================================================
; SETMODE is a resident program which allows you to set the video mode
; and the communication port protocol. PC Magazine July, 1988
;----------------------------------------------------------------------
; BIOS_SEG is the ROM-BIOS data area
;----------------------------------------------------------------------
BIOS_SEG SEGMENT AT 0040H
ORG 0010H
EQUIP_FLAG DW ?
ORG 0049H
CRT_MODE DB ?
COLUMNS DB ? ;Current number of columns
ORG 0050H
CURSOR_POSN DW 8 DUP(?) ;Current cursor location
ORG 0062H
ACTIVE_PAGE DB ? ;Active page for CGA and EGA
ORG 0084H
ROWS DB ? ;Last row number for EGA
DW ?
EGA_INFO DB ?
BIOS_SEG ENDS
CSEG SEGMENT
ASSUME CS:CSEG, DS:CSEG, ES:CSEG
ORG 0100H ;Beginning for .COM programs
START: JMP INITIALIZE ;Initialization code is at end
;----------------------------------------------------------------------
; Data area used by this program
;----------------------------------------------------------------------
HOTKEY EQU 32H ;Scan code for "M" key
SHIFT_MASK EQU 00001000B ;Mask for ALT key
CR EQU 13
LF EQU 10
COPYRIGHT DB "SETMODE 1.0 (c) 1988 Ziff Communications Co."
DB CR,LF,"PC Magazine ",254," Tom Kihlken"
DB CR,LF,"Hotkey is Alt-M$",1AH
INSTALLED_MSG DB CR,LF,"Already Installed$"
WINDOW_TEXT DB 2, 1,"SETMODE 1.0 "
DB 24,32,25,32,26,32,27," + - <CR> Esc",0
DB 4, 4,"COMMUNICATION PORTS",0
DB 2, 5,"Port:",0
DB 16,5,"1",0
DB 23,5,"2",0
DB 30,5,"3",0
DB 37,5,"4",0
DB 2, 6,"Bps:",0
DB 2, 7,"Parity:",0
DB 2, 8,"Data bits:",0
DB 2, 9,"Stop Bits:",0
DB 2,10,"DSR:",0
DB 4,13,"DISPLAY",0
DB 4,14,"Mode:",0
DB 2,15,"0 1 2 3 4 5 6 7 13 14 15 16 17 18 19",0,0
COUNTER1 DB ?
COUNTER2 DB ?
BUSY_FLAG DB 0
COLORS LABEL WORD
NORMAL DB ?
INVERSE DB ?
OLDINT09 DD ?
LEFT_SIDE DB ?
MODE_SELECT DB ?
GRAPH_TEXT DB ?
ITEM_SELECT DB 0
PORT_SELECT DB 0
PORT_ADDRESS DW ?
ADAPTER_FLAGS DB ?
ADAPTER_TABLE DB 54,54,54,54,54,54,54,25,00,00,00,00,00,20,20
DB 24,20,48,16,48
EQUIP_TABLE DB 16,16,32,32,32,32,32,48,00,00,00,00,00,16,16
DB 48,16,32,32,32
;----------------------------------------------------------------------
; This is the main routine of the resident portion of the code
;----------------------------------------------------------------------
SETMODE PROC NEAR
ASSUME CS:CSEG, DS:CSEG, ES:BIOS_SEG
CALL GET_CURS_ADDR ;Cursor address for this page
PUSH ES:[BX] ;Save the cursor location
MOV AL,ES:CRT_MODE ;Get current mode
AND AL,01111111B ;Mask the high bit
MOV MODE_SELECT,AL ;Store the initial video mode
MOV GRAPH_TEXT,1
MOV BX,7007H ;Colors for mono mode
CMP AL,07H ;In mono text mode?
JE NOT_COLOR_TEXT
MOV BX,0503H ;Colors for graphics modes
MOV GRAPH_TEXT,0
CMP AL,3 ;In CGA text mode?
JA NOT_COLOR_TEXT
MOV GRAPH_TEXT,1
MOV BH,ES:ACTIVE_PAGE
MOV AH,8 ;Read current colors
INT 10H ;BIOS read char/attribute
MOV BL,AH ;Foreground color
MOV BH,AH ;Background color
XOR BH,1110111B ;Flip the color bits
NOT_COLOR_TEXT:
MOV COLORS,BX
MOV DI,OFFSET WINDOW_BUFFER
MOV DL,ES:COLUMNS ;Compute center of screen
SUB DL,40 ;We'll use 40 columns
SHR DL,1 ;Divide by two
MOV LEFT_SIDE,DL ;This is column for left edge
XOR DH,DH ;First window in row 0
MOV COUNTER1,1
CALL OPEN_WINDOW ;Open top window
MOV COUNTER1,6
CALL OPEN_WINDOW ;Open middle window
MOV COUNTER1,3
CALL OPEN_WINDOW ;Open bottom window
MOV SI,OFFSET WINDOW_TEXT
TEXT_LOOP:
LODSW ;Fill in window text
OR AL,AL
JZ TEXT_DONE ;Is this the last string yet?
MOV DX,AX ;Get row/column for this string
ADD DL,LEFT_SIDE ;Add in left edge of window
CALL TTY_STRING ;Put up the string
JMP TEXT_LOOP ;Loop for all text strings
TEXT_DONE:
CMP ES:CRT_MODE,19 ;Is this mode 0-19?
JA GET_A_KEY ;If not, can't point to it
CALL VIDEO_COLUMN ;Get column for current mode
INC DL
MOV DH,16
MOV AL,30 ;ASCII for up carrot
CALL DISPLAY_NORMAL ;Pointer to current mode
GET_A_KEY:
CALL SHOW_PORTS ;Display comm port status
CALL SHOW_MODE ;Display video info
MOV CH,INVERSE
CALL REV_BAR ;Inverse video for selected item
XOR AH,AH
INT 16H ;Read a keystroke
PUSH AX ;Save the keystroke
MOV CH,NORMAL
CALL REV_BAR ;Turn off reverse bar
POP AX ;Get back the keystroke
CMP AH,48H ;Is it up arrow ?
JNE NOT_UP
CMP WORD PTR ES:[0000],0 ;Is there a COMM1?
JZ GET_A_KEY ;If not, don't go up
DEC ITEM_SELECT ;Move up to next item
JNS GET_A_KEY
MOV ITEM_SELECT,4
JMP GET_A_KEY ;And get another keystroke
NOT_UP:
CMP AH,50H ;Is it down arrow?
JNE NOT_DOWN
INC ITEM_SELECT ;Move down to next item
CMP ITEM_SELECT,4
JBE GET_A_KEY
MOV ITEM_SELECT,0
JMP GET_A_KEY
NOT_DOWN:
CMP AH,4DH ;Is it right arrow?
JNE NOT_RIGHT
MOV AL,1 ;Indicate moving to right
CALL SIDEWAYS ;And move the bar
NOT_RIGHT:
CMP AH,4BH ;Is it left arrow?
JNE NOT_LEFT
MOV AL,-1 ;Indicate moving to left
CALL SIDEWAYS ;And move the bar
NOT_LEFT:
CMP AL,"+" ;Is it the plus key?
JNE NOT_PLUS
MOV CL,1 ;Indicate increasing value
JMP CHG_COMM
NOT_PLUS:
CMP AL,"-" ;Is it the minus key?
JNE NOT_MINUS
MOV CL,-1 ;Indicate decrease value
JMP CHG_COMM
NOT_MINUS:
CMP AH,1 ;Is it escape?
JE ESC_OUT
CMP AL,13 ;Is it carriage return?
JE EXIT_OUT
JMP GET_A_KEY ;Ignore any other keys
ESC_OUT:
MOV AL,ES:CRT_MODE ;Get starting video mode
MOV MODE_SELECT,AL ;Make it the selected mode
EXIT_OUT:
XOR DH,DH ;Restore the window
MOV SI,OFFSET WINDOW_BUFFER
ROW_LOOP:
MOV CX,40 ;Do all 40 columns
MOV DL,LEFT_SIDE
COL_LOOP:
LODSW
CALL DISPLAY_CHAR
LOOP COL_LOOP ;Loop for each column
INC DH ;Move to next row
CMP DH,18
JNE ROW_LOOP ;Loop for each row
CALL GET_CURS_ADDR ;Get cursor address for this page
POP ES:[BX] ;Restore original cursor position
MOV BL,MODE_SELECT ;Get starting video mode
CMP BL,ES:CRT_MODE ;Has it changed?
JE SAME_MODE ;If not, just return
XOR BH,BH
MOV CL,EQUIP_TABLE[BX]
MOV AX,ES:EQUIP_FLAG
AND AL,11001111B ;Erase old video settings
OR AL,CL ;Set new video equipment bits
MOV ES:EQUIP_FLAG,AX;Write new equipment word
MOV AX,BX
INT 10H ;Reinitialize video adapter
MOV AH,2
XOR DX,DX ;Put cursor at home
XOR BH,BH ;For page zero
INT 10H ;BIOS set cursor function
SAME_MODE:
RET
SETMODE ENDP
;----------------------------------------------------------------------
; Sideways moves the moving bar left and right
;----------------------------------------------------------------------
SIDEWAYS PROC NEAR
ASSUME CS:CSEG, DS:CSEG, ES:BIOS_SEG
CMP ITEM_SELECT,0 ;Doing video modes?
JE CHG_MODE ;If yes then change the mode
MOV BL,PORT_SELECT ;Get comm port number
ADD BL,AL ;Move to next port
MOV PORT_SELECT,BL
CMP BL,3 ;Maximum of 3 ports
JA SIDEWAYS
XOR BH,BH
SHL BX,1
CMP WORD PTR ES:[BX],0 ;Is there a card installed?
JZ SIDEWAYS ;If no card move to next
RET
CHG_MODE:
CMP ADAPTER_FLAGS,0
JE UNKNOWN_ADAPTER
MOV BL,MODE_SELECT ;Get current mode
ADD BL,AL ;Move to next one
MOV MODE_SELECT,BL
CMP BL,19 ;Last mode is number 19
JA CHG_MODE
XOR BH,BH
MOV CL,ADAPTER_TABLE[BX]
AND CL,ADAPTER_FLAGS ;Is this adapter installed?
JZ CHG_MODE ;If not, use next mode
UNKNOWN_ADAPTER:
RET
SIDEWAYS ENDP
;----------------------------------------------------------------------
; CHG_COMM changes the parameters of the serial ports
;----------------------------------------------------------------------
CHG_COMM PROC NEAR
ASSUME CS:CSEG, DS:CSEG, ES:BIOS_SEG
MOV BL,PORT_SELECT ;Look at current port
XOR BH,BH
SHL BX,1
MOV DX,ES:[BX] ;Get the card address
ADD DX,3 ;Point to line control
MOV AH,ITEM_SELECT
DEC AH ;Changing baudrate?
JZ CHG_BAUD
DEC AH ;Doing parity change?
JZ CHG_PARITY
DEC AH ;Changing data bits
JZ CHG_DATA_BITS
DEC AH ;Changing stop bits
JZ CHG_STOP_BITS
JMP GET_A_KEY
CHG_BAUD:
CALL READ_SET_BPS ;Read current baudrate
CMP CL,1
JNE LOWER_BAUD ;Going up?
CMP BX,3 ;At 38400 bps?
JNE SHIFT_DOWN
INC BX ;This is to get 57600 bps
SHIFT_DOWN:
SHR BX,1 ;Divide by two for new rate
OR BX,BX ;Is divisor zero yet?
JNZ SET_NEW_BAUD
MOV BX,384 ;Divisor for 300 bps
JMP SHORT SET_NEW_BAUD
LOWER_BAUD:
SHL BX,1 ;Times two for new rate
CMP BX,4 ;At 28800 bps?
JNE SHIFT_UP
DEC BX ;This is to get 38400 bps
SHIFT_UP:
CMP BX,384 ;At 300 bps yet?
JBE SET_NEW_BAUD
MOV BX,1 ;Set divisor to 1
SET_NEW_BAUD:
CALL READ_SET_BPS ;Set the new value
JMP GET_A_KEY ;And get another keystroke
CHG_PARITY:
IN AL,DX ;Get current parity bits
MOV BL,AL
AND AL,11000111B ;Erase old parity bits
SHR BL,1 ;Shift parity bits over
SHR BL,1
SHR BL,1
CHG_AGAIN:
ADD BL,CL ;Add in the change
AND BL,00000111B
TEST BL,00000001B
JNZ PARITY_OK
TEST BL,00000110B
JNZ CHG_AGAIN ;Skip meaningless settings
PARITY_OK:
SHL BL,1 ;Move parity bits back left
SHL BL,1
SHL BL,1
OR AL,BL ;Replace other starting bits
JMP SHORT CHG_COMM_RET
CHG_DATA_BITS:
IN AL,DX ;Get line control register
MOV AH,AL ;Save original line control
AND AH,11111100B ;Mask out old data bits
ADD AL,CL
AND AL,00000011B ;These are the new data bits
OR AL,AH ;Put back other starting bits
JMP SHORT CHG_COMM_RET
CHG_STOP_BITS:
IN AL,DX ;Get line control register
XOR AL,00000100B ;Toggle the stop bit flag
CHG_COMM_RET:
OUT DX,AL ;Set new line status
JMP GET_A_KEY
CHG_COMM ENDP
;----------------------------------------------------------------------
; REV_BAR turns the moving bar off and on
;----------------------------------------------------------------------
BAR_SIZE DB 0,6,5,1,1
REV_BAR PROC NEAR
ASSUME CS:CSEG, DS:CSEG, ES:BIOS_SEG
MOV DH,ITEM_SELECT ;Get selected item
OR DH,DH ;Are we in video mode row?
JZ DOING_VIDEO ;If yes then use video bar
MOV BL,DH ;BL has item number
XOR BH,BH
MOV CL,BAR_SIZE[BX] ;Get size of this bar
ADD DH,5
MOV AL,7
MUL PORT_SELECT
ADD AL,17
SUB AL,CL
ADD AL,LEFT_SIDE
MOV DL,AL
REV_LOOP:
CALL READ_CHAR ;Read current char at this position
MOV AH,CH ;Change the attribute
CALL DISPLAY_CHAR ;Then write the character again
DEC CL
JNZ REV_LOOP
DONT_SHOW_IT:
RET
DOING_VIDEO:
CMP MODE_SELECT,19 ;Is this mode in normal range
JA DONT_SHOW_IT ;If not, just skip it
CALL VIDEO_COLUMN ;Find column for this mode
MOV DH,15 ;Video is on row 15
MOV CL,2 ;Size of bar is two columns
JMP REV_LOOP
REV_BAR ENDP
;----------------------------------------------------------------------
; VIDEO_COLUMN returns the column position for the selected video mode
;----------------------------------------------------------------------
COLUMN_DATA DB 1,3,5,7,9,11,13,15,0,0,0,0,0,18,21,24,27,30,33,36
VIDEO_COLUMN PROC NEAR
ASSUME CS:CSEG, DS:CSEG, ES:BIOS_SEG
MOV BL,MODE_SELECT ;Get selected mode
XOR BH,BH
MOV DL,COLUMN_DATA[BX]
ADD DL,LEFT_SIDE ;Add in column of left side
RET
VIDEO_COLUMN ENDP
;----------------------------------------------------------------------
; OPEN_WINDOW draws a box with the double line border
;----------------------------------------------------------------------
OPEN_WINDOW PROC NEAR
ASSUME CS:CSEG, DS:CSEG, ES:NOTHING
OR DH,DH
JZ TOP_LINE
MOV AL," "
MOV CX," "*256+" "
CALL OPEN_LINE ;Open a blank line
TOP_LINE:
MOV AL,201
MOV CX,187*256+205
CALL OPEN_LINE ;Top line
WIN_LOOP2:
MOV AL,186
MOV CX,186*256+" "
CALL OPEN_LINE ;Middle lines
DEC COUNTER1
JNZ WIN_LOOP2
MOV AL,200
MOV CX,188*256+205
CALL OPEN_LINE ;Bottom line
RET
OPEN_WINDOW ENDP
;----------------------------------------------------------------------
; OPEN_LINE is used by OPEN_WINDOW to create one row of the window
;----------------------------------------------------------------------
OPEN_LINE PROC NEAR
ASSUME CS:CSEG, DS:CSEG, ES:BIOS_SEG
MOV DL,LEFT_SIDE
CALL SAVE_CHAR
MOV COUNTER2,38
MIDDLE_LOOP:
MOV AL,CL
CALL SAVE_CHAR
DEC COUNTER2
JNZ MIDDLE_LOOP
MOV AL,CH
CALL SAVE_CHAR
INC DH
RET
OPEN_LINE ENDP
;----------------------------------------------------------------------
; SAVE_CHAR stores a character from the screen and displays a new char
;----------------------------------------------------------------------
SAVE_CHAR PROC NEAR
ASSUME CS:CSEG, DS:CSEG, ES:BIOS_SEG
PUSH AX ;Save the new character
CALL READ_CHAR ;Read the existing character
CMP GRAPH_TEXT,1
JE MODE_TEXT1
MOV AH,NORMAL ;Use normal foreground color
MODE_TEXT1:
MOV DS:[DI],AX ;And store it in the buffer
INC DI
INC DI
POP AX ;Get back new character
CMP GRAPH_TEXT,1
JE MODE_TEXT2
TEST AL,10000000B ;Is this a high bit character
JZ MODE_TEXT2 ;If not, just continue
MOV AL,"*" ;If it is, reset it to "*"
MODE_TEXT2:
CALL DISPLAY_NORMAL ;Put up the new character
RET
SAVE_CHAR ENDP
;----------------------------------------------------------------------
; TTY_STRING displays an ASCII string terminated with a byte of zero
;----------------------------------------------------------------------
TTY_STRING PROC NEAR
ASSUME CS:CSEG, DS:CSEG, ES:BIOS_SEG
LODSB
OR AL,AL
JZ TTY_RET
CALL DISPLAY_NORMAL
JMP TTY_STRING
TTY_RET:
RET
TTY_STRING ENDP
;----------------------------------------------------------------------
; DISPLAY routines display a character using a BIOS function call
;---------------------------------------------------------------------
DISPLAY_NORMAL PROC NEAR
ASSUME CS:CSEG, DS:CSEG, ES:BIOS_SEG
MOV AH,NORMAL
DISPLAY_CHAR:
PUSH BX
PUSH CX
CALL GET_CURS_ADDR ;Get address of BIOS cursor
MOV ES:[BX],DX ;Tell BIOS where the cursor is
MOV BL,AH ;Get back the attribute
MOV BH,ES:ACTIVE_PAGE ;Get active page
MOV CX,1 ;Write 1 character
MOV AH,9 ;Write character and attribute
INT 10H
POP CX
POP BX
INC DL ;Advance the cursor column
RET ;Done writing the character
DISPLAY_NORMAL ENDP
;----------------------------------------------------------------------
; READ_CHAR reads a character from the screen
;---------------------------------------------------------------------
READ_CHAR PROC NEAR
ASSUME CS:CSEG, DS:CSEG, ES:BIOS_SEG
CALL GET_CURS_ADDR ;Get address of BIOS cursor
MOV ES:[BX],DX ;Tell BIOS where the cursor is
MOV BH,ES:ACTIVE_PAGE ;Get active page
MOV AH,8 ;BIOS function to read character
INT 10H ;Read the character/attribute
RET
READ_CHAR ENDP
;----------------------------------------------------------------------
; GET_CURS_ADDR finds the address of the cursor for current video page
;---------------------------------------------------------------------
GET_CURS_ADDR PROC NEAR
ASSUME CS:CSEG, DS:CSEG, ES:BIOS_SEG
MOV BL,ES:ACTIVE_PAGE ;Get the current page number
XOR BH,BH ;Convert to a word offset
SHL BX,1 ;Times two for a word
ADD BX,OFFSET CURSOR_POSN ;Add in base address
RET
GET_CURS_ADDR ENDP
;---------------------------------------------------------------------
YES_TXT DB "Yes",0
NO_TXT DB " No",0
NA_TXT DB "n/a",0
NONE_TXT DB " None",0
ODD_TXT DB " Odd",0
EVEN_TXT DB " Even",0
SPACE_TXT DB "Space",0
MARK_TXT DB " Mark",0
PARITY_TABLE DW OFFSET ODD_TXT, OFFSET EVEN_TXT
DW OFFSET SPACE_TXT, OFFSET MARK_TXT
;----------------------------------------------------------------------
; SHOW_PORTS displays the current settings of all comm ports
;----------------------------------------------------------------------
SHOW_PORTS PROC NEAR
ASSUME CS:CSEG, DS:CSEG, ES:BIOS_SEG
XOR BX,BX
MOV COUNTER1,BL ;Start with first comm port
PORT_LOOP:
MOV AL,7 ;Seven columns per port column
MUL BL
SHR AL,1
MOV CX,6*256+16 ;Row/column for first item
ADD CL,LEFT_SIDE ;Add in column of left edge
ADD CL,AL ;And shift over to correct column
MOV DX,ES:[BX] ;Retrive the comm port address
MOV BP,DX ;And save it here
OR DX,DX ;Is there a card installed?
JNZ GOT_CARD ;If yes, display its status
MOV SI,OFFSET NA_TXT
MOV DX,CX ;Get row/column for this entry
SUB DL,2
CALL TTY_STRING ;Display "n/a" text
JMP NEXT_PORT ;And go on to next port
GOT_CARD:
MOV AL,"0" ;Put a zero in bps column
MOV DX,CX
CALL DISPLAY_NORMAL ;Display the zero
MOV DX,BP
ADD DX,3 ;Point to line control register
CALL READ_SET_BPS ;Read the current baud rate
PUSH BX ;Save it
CALL READ_SET_BPS ;Restore original baud settings
POP BX ;Now we have the bps in BX
OR BX,BX ;Is it set to zero?
JZ NO_BPS_SET ;If yes, just skip it
XOR DX,DX
MOV AX,11520
DIV BX
MOV COUNTER2,6 ;Display five digits
PUSH CX
MOV SI,CX ;Save cursor position
MOV BX,10
MOV DX,AX
XOR AX,AX
CHAR_LOOP:
MOV CX,DX
XOR DX,DX
DIV BX
XCHG AX,CX
DIV BX
XCHG AX,DX
ADD AL,"0" ;Convert this digit to ASCII
PUSH DX
DEC SI ;Backup cursor position
MOV DX,SI
CALL DISPLAY_NORMAL ;Display this digit
DEC COUNTER2
POP DX
MOV AX,CX
OR CX,DX
JNZ CHAR_LOOP
MOV DX,SI
FILL_BLANKS:
DEC DL
MOV AL," "
CALL DISPLAY_NORMAL
DEC DL
DEC COUNTER2
JNZ FILL_BLANKS
POP CX
NO_BPS_SET:
MOV DX,BP ;Get back the port address
ADD DX,3 ;Line control register
IN AL,DX
PUSH AX ;Save starting status
MOV SI,OFFSET NONE_TXT
TEST AL,00001000B ;Look at parity enable bit
JZ NO_PARITY
AND AX,00110000B ;Look at parity bits
SHR AX,1
SHR AX,1
SHR AX,1
MOV SI,AX
MOV SI,PARITY_TABLE[SI]
NO_PARITY:
MOV DX,CX
SUB DL,4
ADD DH,1
CALL TTY_STRING ;Display parity status
POP AX
PUSH AX ;Get line control status again
AND AL,00000011B ;Look at data bits
ADD AL,35H ;Convert it to ASCII code
MOV DX,CX
ADD DH,2
CALL DISPLAY_NORMAL
POP DX
PUSH DX ;Get line control status again
MOV AL,"1" ;Assume one stop bit
TEST DL,00000100B ;Are two stop bits used?
JZ ONE_STOP
INC AL
ONE_STOP:
MOV DX,CX
ADD DH,3
CALL DISPLAY_NORMAL
MOV DX,BP
ADD DX,6 ;Point to modem status register
IN AL,DX
MOV SI,OFFSET NO_TXT
TEST AL,00100000B ;Is bit five set?
JZ NO_DSR ;If not, DSR is not on
MOV SI,OFFSET YES_TXT
NO_DSR:
MOV DX,CX
ADD DH,4
SUB DL,2
CALL TTY_STRING
POP AX
MOV DX,BP ;Get back the card adress
ADD DX,3
OUT DX,AL ;Restore the line status register
NEXT_PORT:
MOV BL,COUNTER1
XOR BH,BH
INC BX
INC BX
CMP BL,8 ;Do four comm ports
JAE PORT_DONE
MOV COUNTER1,BL
JMP PORT_LOOP
PORT_DONE:
RET
SHOW_PORTS ENDP
;----------------------------------------------------------------------
; READ_SET_BPS reads the current baud rate and sets a new one
;----------------------------------------------------------------------
READ_SET_BPS PROC NEAR
ASSUME CS:CSEG, DS:NOTHING, ES:NOTHING
IN AL,DX ;Read the line status register
MOV AH,AL ;Save initial line status
MOV AL,80H
OUT DX,AL
SUB DX,3 ;Get to low byte of divisor
IN AL,DX
XCHG BL,AL
OUT DX,AL ;Write the high byte of divisor
INC DX ;Get to high byte of divisor
IN AL,DX
XCHG BH,AL
OUT DX,AL ;Write the high byte of divisor
INC DX ;Back to line status register
INC DX
MOV AL,AH ;Get back original line status
OUT DX,AL ;And restore it
RET
READ_SET_BPS ENDP
;----------------------------------------------------------------------
COLOR_TABLE DB 1,2,1,2,2,1,1,3,2,2,3,2,1,2,2
RES_TABLE DW OFFSET RES_1, OFFSET RES_1, OFFSET RES_2
DW OFFSET RES_2, OFFSET RES_3, OFFSET RES_3
DW OFFSET RES_4, OFFSET RES_2, OFFSET RES_5
DW OFFSET RES_4, OFFSET RES_6, OFFSET RES_6
DW OFFSET RES_7, OFFSET RES_7, OFFSET RES_5
RES_1 DB "25x40 ",0
RES_2 DB "25x80 ",0
RES_3 DB "320x200",0
RES_4 DB "640x200",0
RES_5 DB "320x200",0
RES_6 DB "640x350",0
RES_7 DB "640x480",0
TEXT_TXT DB "Text ",0
GRAPH_TXT DB "Graph",0
COLOR_TXT DB "Color",0
MONO_TXT DB "Mono ",0
BW_TXT DB "B/W ",0
;----------------------------------------------------------------------
; SHOW_MODE displays the selected video mode number and resolution
;----------------------------------------------------------------------
SHOW_MODE PROC NEAR
ASSUME CS:CSEG, DS:CSEG, ES:BIOS_SEG
MOV BL,MODE_SELECT ;Get selected mode
MOV DH,14 ;Put text on row 14
MOV DL,LEFT_SIDE
ADD DL,9
MOV AL,BL ;Current mode into AL
MOV CL,10
XOR AH,AH
DIV CL ;Divide by 10
MOV BH,AH ;Save remainder for next digit
OR AL,AL ;Is first digit a zero?
JNZ TWO_DIGITS ;If not, display it normally
MOV AL," " - "0" ;Make first digit a space
TWO_DIGITS:
ADD AL,"0" ;Convert digit to ASCII
CALL DISPLAY_NORMAL ;First digit of mode number
MOV AL,BH
ADD AL,"0"
CALL DISPLAY_NORMAL ;Second digit of mode number
CMP BL,19 ;Is this mode in table?
JA NOT_IN_TABLE
ADD DL,3 ;Skip three spaces
XOR BH,BH
MOV SI,OFFSET TEXT_TXT
CMP BL,7
JE TEXT_MODE
JB NOT_EGA_MODE
SUB BL,5
NOT_EGA_MODE:
CMP BL,3
JBE TEXT_MODE
MOV SI,OFFSET GRAPH_TXT
TEXT_MODE:
CALL TTY_STRING ;Show text/graph mode
INC DL ;Skip a space
MOV AL,COLOR_TABLE[BX]
MOV SI,OFFSET BW_TXT
DEC AL
JZ SHOW_COLOR
MOV SI,OFFSET COLOR_TXT
DEC AL
JZ SHOW_COLOR
MOV SI,OFFSET MONO_TXT
SHOW_COLOR:
CALL TTY_STRING ;Show color/bw mode selected
INC DL ;Skip a space
SHL BX,1
MOV SI,RES_TABLE[BX]
CALL TTY_STRING ;Display resolution of this mode
NOT_IN_TABLE:
RET
SHOW_MODE ENDP
;----------------------------------------------------------------------
; Interrupt 09 routine. watch for trigger key to pop up.
;----------------------------------------------------------------------
NEWINT09 PROC FAR
ASSUME CS:CSEG, DS:NOTHING, ES:NOTHING
STI ;Allow other interrupts
PUSHF
PUSH AX ;Must save processor state
IN AL,60H ;Get the scan code
CMP AL,HOTKEY ;Is it the hot key?
JE TRIGGER ;If yes, check the mask
INT09_EXIT: POP AX ;Restore the processor state
POPF
JMP CS:OLDINT09 ;Continue with ROM routine
TRIGGER: MOV AH,2 ;Get keyboard status
INT 16H ;BIOS keyboard service
AND AL,0FH ;Test only for shift keys
CMP AL,SHIFT_MASK ;Does it match out combination?
JNE INT09_EXIT ;If not, ignore it
CMP CS:BUSY_FLAG,0 ;Is SETMODE already active?
JNZ INT09_EXIT ;If active, then exit
INC CS:BUSY_FLAG ;Its active now
IN AL,61H ;These instructions reset KB
MOV AH,AL
OR AL,80H
OUT 61H,AL
MOV AL,AH
JMP SHORT KB_DELAY
KB_DELAY:
OUT 61H,AL
CLI
MOV AL,20H
OUT 20H,AL ;Reset the interrupt controller
STI
PUSH BX ;Must preserve all registers
PUSH CX
PUSH DX
PUSH BP
PUSH SI
PUSH DI
PUSH DS
PUSH ES
PUSH CS
POP DS ;Set DS to CSEG
MOV AX,BIOS_SEG ;ES points to BIOS data area
MOV ES,AX
ASSUME DS:CSEG, ES:BIOS_SEG
CALL SETMODE ;Do the window
DEC BUSY_FLAG
POP ES ;Restore all registers
POP DS
ASSUME DS:NOTHING, ES:NOTHING
POP DI
POP SI
POP BP
POP DX
POP CX
POP BX
POP AX
POPF
IRET ;Now were all done
NEWINT09 ENDP
;--------------------------------------------------------------------
; Here is the code used to initialize setmode
;--------------------------------------------------------------------
ASSUME CS:CSEG, DS:CSEG, ES:CSEG
EVEN ;Align the buffer
WINDOW_BUFFER LABEL BYTE
INITIALIZE:
MOV DX,OFFSET COPYRIGHT ;Do first half of copyright
MOV AH,9
INT 21H
MOV AX,1A00H ;Read display combination code
INT 10H
CMP AL,1AH ;Is VGA or MCGA present?
JNE NO_VGA
MOV AH,00100000B ;Set bit for MCGA adapter
CMP BL,0BH ;Is it model 30 with mono?
JE SET_BITS
CMP BL,0CH ;Is it model 30 with color?
JE SET_BITS
MOV AH,00010000B ;Set bit for VGA adapter
CMP BL,7 ;Is it VGA mono?
JE SET_BITS
CMP BL,8 ;Is it VGA color?
JE SET_BITS
NO_VGA:
XOR DH,DH
MOV AH,0B8H ;Look for a color adapter
CALL LOOK_FOR_CARD
JNE NO_COLOR
OR DH,00000010B ;Set bit for color adapter
NO_COLOR:
MOV AH,0B0H ;Look for mono adapter
CALL LOOK_FOR_CARD
JNE NO_MONO
OR DH,00000001B ;Set bit for mono adapter
NO_MONO:
MOV ADAPTER_FLAGS,DH
MOV AH,12H
MOV BL,10H ;BIOS get EGA info function
INT 10H
CMP BL,10H ;Did BL change?
JE NOT_EGA ;If not, no EGA present
PUSH ES
MOV AX,BIOS_SEG
MOV ES,AX
ASSUME ES:BIOS_SEG
MOV AH,00000100B ;Set bit for EGA color
TEST ES:EGA_INFO,00000010B ;Is an EGA mono attached?
POP ES
ASSUME ES:CSEG
JZ SET_BITS
MOV AH,00001000B ;Set bit for EGA mono only
SET_BITS:
OR ADAPTER_FLAGS,AH
NOT_EGA:
; Search for an previously installed copy of setmode
NOT BYTE PTR START ;Modify to avoid false match
XOR BX,BX ;Start search at segment zero
MOV AX,CS ;Compare to this code segment
NEXT_SEGMENT:
INC BX ;Look at next segment
CMP AX,BX ;Until reaching this code segment
MOV ES,BX
JE NOT_INSTALLED
MOV SI,OFFSET START ;Setup to compare strings
MOV DI,SI
MOV CX,16 ;16 bytes must match
REP CMPSB ;Compare DS:SI to ES:DI
OR CX,CX ;Did the strings match?
JNZ NEXT_SEGMENT ;If no match, try next segment
MOV DX,OFFSET INSTALLED_MSG
ERR_EXIT: MOV AH,9 ;DOS display string service
INT 21H ;Display error message
MOV AX,4C01H ;Return error code
INT 21H ;Exit to DOS
NOT_INSTALLED:
ASSUME ES:NOTHING
MOV AX,3509H ;Get keyboard vector
INT 21H
MOV WORD PTR [OLDINT09], BX ;Save segment
MOV WORD PTR [OLDINT09+2],ES ;Save offset
MOV DX,OFFSET NEWINT09
MOV AX, 2509H
INT 21H ;DOS function to change vector
;----------------------------------------------------------------------
; Deallocate our copy of the enviornment. Terminate
; and stay resident. Leave code and space for buffer resident.
;----------------------------------------------------------------------
MOV AX,DS:[002CH] ;Get segnemt of enviornment
MOV ES,AX ;Put it into ES
MOV AH,49H ;Release allocated memory
INT 21H
MOV DX,OFFSET WINDOW_BUFFER + 40*18*2 + 15
MOV CL,4 ;Shift four to divide by 16
SHR DX,CL ;Convert size to paragraphs
MOV AX,3100H ;Return success status
INT 21H
;---------------------------------------------------------------------
; This routine examines memory to look for a display card.
;---------------------------------------------------------------------
LOOK_FOR_CARD PROC NEAR
ASSUME CS:CSEG, DS:NOTHING, ES:NOTHING
XOR SI,SI ;Look at offset zero
PUSH DS
XOR AL,AL
MOV DS,AX ;Load the segment register
MOV CH,[SI] ;Store the initial value
MOV AL,55H
MOV [SI],AL ;Write pattern of ones and zeros
JMP SHORT DELAY ;A short delay
DELAY:
MOV AH,[SI] ;Read the byte we just wrote
MOV [SI],CH ;Restore the initial value
POP DS
CMP AL,AH ;Did it match?
RET
LOOK_FOR_CARD ENDP
CSEG ENDS
END START